#pragma once
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>
#include "Initadd.h"
#define BACKLOG 8
#include "comm.h"
#include "Log.h"
#include "ThreadPool.h"
static const uint16_t gport = 8081;
using namespace LogMudule;
using namespace ThreadPoolMoudle;

using handler_t = std::function<std::string(std::string &)>;
class Tcpserve
{
    using task_t = std::function<void()>;
    struct ThreadData
    {
        int sockfd;
        Tcpserve *self;
    };

public:
    Tcpserve(handler_t handler, int potr = gport)
        : _handler(handler), _port(potr), _isrunning(false)
    {
    }
    void init()
    {
        listentsocket = ::socket(AF_INET, SOCK_STREAM, 0);
        if (listentsocket < 0)
        {
            LOG(LogLevel::FATAL) << "socket error" << listentsocket;
            Die(1);
        }

        LOG(LogLevel::INFO) << "socket success " << listentsocket;
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(gport);
        local.sin_addr.s_addr = INADDR_ANY;

        // TODO:
        int opt = 1;
        setsockopt(listentsocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(local));
        setsockopt(listentsocket, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(local));

        // 3 bind
        int n = bind(listentsocket, CONV(&local), sizeof(local));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            Die(2);
        }
        LOG(LogLevel::INFO) << "bind success->:" << listentsocket;
        // 4 监听
        n = listen(listentsocket, BACKLOG);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            Die(1);
        }
        LOG(LogLevel::INFO) << "listen success->:" << listentsocket;
    }
    void HanderRequest(int sockfd)
    {
        LOG(LogLevel::INFO) << "HandlerRequest, sockfd is : " << sockfd;
        char buffer[1024];
        std::string package;
        while (1)
        {
            // ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                LOG(LogLevel::INFO) << "\n"
                                    << buffer;
                package += buffer;
                // std::string echo_str = "serve echo#";
                // echo_str += buffer;
                // LOG(LogLevel::INFO) << buffer;
                // write(sockfd, echo_str.c_str(), echo_str.size());

                std::string echo_str = _handler(package);
                if (echo_str.empty())
                    continue; // TODO
                send(sockfd, echo_str.c_str(), echo_str.size(), 0);
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "socket quit->:" << sockfd;
                break;
            }
            else
            {
                break;
            }
        }
        close(sockfd);
    }
    static void *ThreadEntry(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = (ThreadData *)args;
        data->self->HanderRequest(data->sockfd);

        return nullptr;
    }
    void start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            int socker = ::accept(listentsocket, CONV(&peer), &peerlen);
            if (socker < 0)
            {
                LOG(LogLevel::WARNING) << "accept error";
                continue;
            }
            LOG(LogLevel::INFO) << "accept success is->:" << socker;
            IntAddr addr(peer);
            LOG(LogLevel::INFO) << "client info: " << addr.Addr();
            // version 1 单进程
            // HanderRequest(socker);

            // version 2 多进程
            // pid_t _id = fork();
            // if (_id == 0)
            // {
            //     close(listentsocket);
            //     if (fork() > 0)
            //     {
            //         exit(0);
            //     }
            //     HanderRequest(socker);
            //     exit(0);
            // }
            // close(socker);
            // int rid = waitpid(_id, nullptr, 0);
            // if (rid < 0)
            // {
            //     LOG(LogLevel::ERROR) << "waidpid error";
            // }
            // version 3 多线程
            // pthread_t tid;
            // ThreadData *data = new ThreadData;
            // data->sockfd = socker;
            // data->self = this;
            // pthread_create(&tid, nullptr, ThreadEntry, data);

            // version 4 线程池
            // task_t f = std::bind(&Tcpserve::HanderRequest, this, socker);
            ThreadPool<task_t>::GetInstance()->Equeue([this, socker]()
                                                      { this->HanderRequest(socker); });
        }

        _isrunning = false;
    }
    ~Tcpserve()
    {
    }

private:
    int listentsocket;
    uint16_t _port;
    bool _isrunning;

    handler_t _handler;
};